#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <asm/io.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/irq.h>


static const struct of_device_id maz_input[] = {
    {
        .compatible = "maz, input",
    },
    {},
};

struct pin_desc{
	int irq_num;
	char*name;
	unsigned int gpio;
	unsigned int key_val;
	int irq_type;
};

static struct pin_desc maz_pins_desc[5] = {
 	{0,"gpios-l",0, KEY_L, 0},
 	{0,"gpios-s",0, KEY_S, 0},
 	{0,"gpios-ent",0, KEY_ENTER, 0},
    {0,"gpios-bak",0, KEY_BACK, 0},
    {0,"gpios-led",0, LED_MUTE, 0},
};


static struct input_dev *key_led_dev;
static struct timer_list key_timer;
static int g_irq_num;


static irqreturn_t key_led_irq(int irq, void *dev)
{
	g_irq_num = irq;

	mod_timer(&key_timer,jiffies+HZ/100);
	return IRQ_HANDLED;
}
static void key_timer_function(struct timer_list *t)
{

    int pinval=-1;
	int i;
	
	for(i = 0; i < 5; i++) {
		if (maz_pins_desc[i].irq_num == g_irq_num)
			break;
	}
	pinval = gpio_get_value(maz_pins_desc[i].gpio);

    input_report_key(key_led_dev ,maz_pins_desc[i].key_val,pinval);
    //input_event(key_led_dev,EV_KEY,maz_pins_desc[i].key_val,pinval);
    input_sync(key_led_dev);

	printk("[%s][%d] name : %s pinval %d\n",__func__,__LINE__,maz_pins_desc[i].name,pinval);
}


static int key_led_open(struct input_dev *dev)
{
    printk("input key_led open!\n");
    return 0;
}


static int led_event (struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
	printk("[%s][%d]\n",__func__,__LINE__);

    return 0;
}

static int maz_input_probe (struct platform_device * pdev)
{
	int i;
	int err;
	/*1. 分配一个input_dev结构体  */ 
	key_led_dev=input_allocate_device();
    key_led_dev->name = "maz-input";
	/*2. 设置 */
	/*2.1 能产生哪类事件*/
    set_bit(EV_LED, key_led_dev->evbit);
    //set_bit(EV_SND, input_subsys_dev->evbit);//声音事件
    set_bit(EV_KEY,key_led_dev->evbit);
    
    /*2.2 表示能产生哪些事件*/
    set_bit(LED_MUTE,key_led_dev->keybit);
    set_bit(KEY_L,key_led_dev->keybit);
    set_bit(KEY_S,key_led_dev->keybit);    
    set_bit(KEY_ENTER,key_led_dev->keybit);
    set_bit(KEY_BACK,key_led_dev->keybit);
    /* 分配输入设备的open方法，用户操作open(/dev/xxx, ...)时调用 */
    key_led_dev->open = key_led_open;
    /* 分配输入设备的event方法，用户在应用程序write()时 */
    key_led_dev->event = led_event;
    /*3. 注册   */
	err = input_register_device(key_led_dev);
	if(err)
		return err;
    /*4. 硬件相关的操作   */ 
    timer_setup(&key_timer,key_timer_function,0);
	/*5. 解析 dts文件获得GPIO  */

	for (i = 0; i < 5; i++) {
		//获取GPIO 
		maz_pins_desc[i].gpio = of_get_named_gpio(pdev->dev.of_node,maz_pins_desc[i].name,0);
		if(maz_pins_desc[i].gpio < 0) {
				printk("maz_pins_desc %d  can't gpios",i);
				return -EINVAL;
		}
		//获取 中断 type 
		of_property_read_u32_index(pdev->dev.of_node, maz_pins_desc[i].name, 2, &maz_pins_desc[i].irq_type);
		//获取中断号
		maz_pins_desc[i].irq_num = gpiod_to_irq(gpio_to_desc(maz_pins_desc[i].gpio));
		printk("maz_pins_desc %d irq_num : %d",i,maz_pins_desc[i].irq_num);
		
		disable_irq(maz_pins_desc[i].irq_num);//因为pinctrl的原因要先disable下
		enable_irq(maz_pins_desc[i].irq_num);
		err = request_irq(maz_pins_desc[i].irq_num,key_led_irq,maz_pins_desc[i].irq_type,maz_pins_desc[i].name,NULL);
		if(err) {
			printk(KERN_INFO"request_irq  err:%d\n",err);
			return -EINVAL;
		}
		else {
			printk(KERN_INFO"request_irq  successfull\n");
			//irq_flag = 1;
		}
	}
    printk("[%s] ok!\n",__func__);
	return 0;
}

static int maz_input_remove (struct platform_device * dev)
{
	int i;
	for (i = 0; i < 5; i++)
	{
		free_irq(maz_pins_desc[i].irq_num, NULL);
	}
	del_timer(&key_timer);
	input_unregister_device(key_led_dev);
	input_free_device(key_led_dev);
	return 0;
}


/* 分配/设置/注册一个 platform_dirve */

static struct platform_driver input_drv={
	.probe  = maz_input_probe,
	.remove = maz_input_remove,
	.driver = {
		.name   = "maziot, input",
		.owner = THIS_MODULE,
		.of_match_table = maz_input
	},
};


static int  maz_input_init(void)
{
	printk("[%s][%d]\n",__func__,__LINE__);
	platform_driver_register(&input_drv);
	return 0;
}

static void maz_input_exit(void)
{
	printk("[%s][%d]\n",__func__,__LINE__);
	platform_driver_unregister(&input_drv);
}

module_init(maz_input_init);
module_exit(maz_input_exit);
MODULE_LICENSE("GPL");

